/*
 * PlateauImage.java
 *
 */
package Risk.IHM;

import Risk.Moteur.Jeu;
import Risk.Moteur.Pays;
import Risk.Moteur.Plateau;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;

import java.io.File;
import java.io.IOException;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.imageio.ImageIO;

import javax.swing.JPanel;

/**
 * Classe qui dessine l'image de la carte sur le plateau
 * @author Nicoleta Sergi
 */
public class ImageCarte extends JPanel implements MouseMotionListener, MouseListener {
    //variables statiques
    private static final long	serialVersionUID = 1L;
    //marge pour mettre a l'echelle l'ecriture des noms des pays sur la carte
    private static final int	MARGE_TEXTE      = 4;
    //variable de classe
    public static ImageCarte	ma_carte;
    //utilise dans mousemoved pour savoir si la souris survole la même couleur
    //donc si la souris est tjs sur le même pays
    private boolean		bloque          = false;
    // booleens qui permettent de savoir si une option a ete choisie par l'utilisateur
    private boolean	afficherNomPays;
    private boolean	afficherPossessions;
    
    //utilise pour construire la hashtable contenant les couleurs des pays et leur nom
    private Color		oldColor        = Color.white;   

    // hashtables pour stocker les couleurs, les noms, le centre de gravite et les pixels des pays
    private Hashtable<Color, Point>		centresDeGravite;
    private Hashtable<Color, String>		dicoCoulNom;
    private Hashtable<Color, Vector<Point>>	dicoPixels;
    //le nom de l'image de la carte et le nom d'un pays (txt)
    private String				image, txt;

    // l'image de la carte et sa copie de travail
    private BufferedImage                       img, copie;

    // la plateau de la carte
    private PlateauIhm                          pihm;

    // les pays source et destination (utilises dans mousClicked)
    private Pays                                source,	destination;
    private boolean                             surligner_couleur;

    // vecteur des pays ihm de la carte
    private Vector<PaysIHM>                     vPays;

    /**
     * constructeur de la carte de jeu
     * @param descTxtCarte - le fichier *.dat utilise pour la carte
     * @param image - le nom de l'image utilisee
     * @param frame - la frame parent
     */
    public ImageCarte(String descTxtCarte, String image, PlateauIhm frame) {
	super(new BorderLayout());
	ImageCarte.ma_carte = this;
	this.pihm           = frame;
	afficherNomPays     = false;
	afficherPossessions = false;
	surligner_couleur   = true;

	// initialisation du vecteur des pays
	vPays = new Vector<PaysIHM>();

	Scanner	sc;

	try {
	    sc         = new Scanner(new File(descTxtCarte));
	    this.image = image;
	    img        = ImageIO.read(new File(image));

	    // copie de travail de la carte
	    copie = ImageIO.read(new File(image));

	    // dictionnaire des noms et couleurs des pays sur la carte
	    dicoCoulNom = new Hashtable<Color, String>();

	    // dictionnaire des pixels d'une certaine couleur sur la carte
	    // optimisation pour la surbrilance d'un pays en ihm
	    dicoPixels = new Hashtable<Color, Vector<Point>>();

	    while (sc.hasNextLine()) {

		// on recupere une ligne du fichier texte
		String	ligne = sc.nextLine();

		// une ligne = code_rgb;nom_pays
		StringTokenizer	st = new StringTokenizer(ligne, ";");
		int		r  = Integer.parseInt(st.nextToken());
		int		g  = Integer.parseInt(st.nextToken());
		int		b  = Integer.parseInt(st.nextToken());

		// recupere la couleur trouvee dans le fichier texte
		Color	c = new Color(r, g, b);

		// recupere le nom du pays associe a la couleur
		String	nom = st.nextToken();

		// ajout au dictionnaire la couleur et le nom du pays
		dicoCoulNom.put(c, nom);
	    }

	    // remplisage des vecteurs de pixels d'une certaine couleur
	    remplirDicoPixels();
	    centreDeGravite();
	    initPaysIHM();
	} catch (Exception e) {
	    e.printStackTrace();
	}

	addMouseMotionListener(this);
	addMouseListener(this);
    }
    /**
     * methode d'attaque appelee dans mouseClicked
     * @param pays_clic - le pays clique
     */
    private void attaque(Pays pays_clic) {
        //si pays_clic appartient au joueur courant
	if (pays_clic.controlePays(pihm.getRisk().getJoueurCourant())) {
	    if (pays_clic.getNbArmee() > 1) {
		source      = pays_clic;
		destination = null;
		pihm.modifierTexte("Pays Attaquant = " + pays_clic);
	    } else {
		pihm.modifierTexte("Attaque impossible depuis " + pays_clic + " (1 soldat)");
	    }
	} else {    // pays_clic appartient a un joueur adv
	    if (source != null) {
		if (pays_clic.testFrontiere(source)) {
		    destination = pays_clic;
		    pihm.modifierTexte("Pays Attaquant = " + source + "\n Pays defenseur = " + pays_clic);
		} else {
		    pihm.modifierTexte(source + " n a pas de frontiere avec " + pays_clic);
		}
	    } else {
		pihm.modifierTexte("Veuillez choisir un pays que vous controlez !");
	    }
	}
        //met en surbrillance les pays cliques
	surlignerPays();

	// si j'ai choisit ma source et ma destination alors je peux faire le tirage au des
	if ((source != null) && (destination != null)) {
	    pihm.setJBTirDe(true);
	} else {
	    pihm.setJBTirDe(false);
	}
    }

    /**
     * calcul du centre de gravite d'un pays
     */
    public void centreDeGravite() {

	// hashtable qui va contenir la couleur d'un pays et son centre de gravite
	centresDeGravite = new Hashtable<Color, Point>();

	// on parcours chaque couleur de pays qui se trouve dans notre dictionnaire de pixels
	for (Enumeration<Color> e = dicoPixels.keys(); e.hasMoreElements(); ) {

	    // on recupere la couleur et son vecteur des points
	    Color		c      = e.nextElement();
	    Vector<Point>	pixels = dicoPixels.get(c);
	    int			x      = 0;
	    int			y      = 0;

	    for (int i = 0; i < pixels.size(); i++) {
		Point	p = pixels.get(i);

		// calcul de la somme des x et des y pour faire la moyenne
		x += p.x;
		y += p.y;
	    }

	    // le centre de gravite
	    Point	centreDeGravite = new Point(x / pixels.size(), y / pixels.size());

	    // on l'ajoute a la hashtable qui contient les centres de gravite
	    centresDeGravite.put(c, centreDeGravite);

	    // DEBUG
	    // System.out.println(c.getRed()+";"+c.getGreen()+";"+c.getBlue()+
            //          " a comme centre "+centreDeGravite.x+";"+centreDeGravite.y);
	}
    }

    /**
     * met le boolean a false pour desurligner les pays
     */
    public void desurligner() {
	for (int i = 0; i < vPays.size(); i++) {
	    vPays.get(i).clique = false;
	}
    }
    /**
     * les pays source et destination sont mis a null lors de la sortie 
     * d'une phase d'attaque ou de manoeuvre
     */
    public void effaceSelection() {
	destination = null;
	source      = null;
	desurligner();
    }

    /**
     * initialisation des pays sur l'interface graphique
     */
    public void initPaysIHM() {

	// on recupere le plateau de jeu du risk virtuel
	Plateau	plateau = pihm.getRisk().getPlateau();

	// pour tous les pays
	for (Enumeration<Color> e = dicoCoulNom.keys(); e.hasMoreElements(); ) {

	    // on recupere la couleur et le nom du dictionnaire dicoCoulNom
	    Color	c       = e.nextElement();
	    String	nomPays = dicoCoulNom.get(c);

	    // maintenant on a le pays
	    Pays	p = plateau.getPays(nomPays);

	    // DEBUG
	    // System.out.println("Pays : "+nomPays+"= "+p+" couleur : "+c);
	    // on recupere le vecteur des points de la meme couleur
	    Vector<Point>	pixels = dicoPixels.get(c);

	    // DEBUG
	    // if(pixels==null) System.out.println("Pixels est nul !");
	    // on calcule le point correspondant au centre de gravite du pays
	    Point	pCentre = centresDeGravite.get(c);

	    // DEBUG
	    // if(pCentre==null) System.out.println("Pcentre est nul !");
	    PaysIHM	paysIhm = new PaysIHM(p, pixels, c, pCentre.x, pCentre.y);

	    // on l'ajoute au vecteur des paysIHM
	    vPays.add(paysIhm);
	}
    }

    /**
     * mise a jour du texte du nombre d'armees sur le pays conquit
     * @param p - le pays conquit
     */
    public void majCoulTextePays(Pays p) {
	for (int i = 0; i < vPays.size(); i++) {
	    if (vPays.get(i).getPays().getNom().equals(p.getNom())) {
		vPays.get(i).changerCouleurNbArmees();

		break;
	    }
	}
    }

    /**
     * phase manoeuvre
     * @param pays_clic - pays choisi pour deplacer les armees
     */
    private void manoeuvre(Pays pays_clic) {
        //si on a bien clique sur un pays nous appartenant
	if (pays_clic.controlePays(pihm.getRisk().getJoueurCourant())) {
	    if ((getSource() == null) || pays_clic.equals(getSource())) {
		if (pays_clic.getNbArmee() > 1) {
		    setSource(pays_clic);
		    surlignerPays();
		    pihm.modifierTexte("Depart :" + getSource());
		} else {
		    pihm.modifierTexte("Depart impossible depuis " + pays_clic + " (1 soldat)");
		}
	    } else {
		if (pays_clic.testDeplacement(source)) {
		    setDestination(pays_clic);
		    surlignerPays();
		    pihm.modifierTexte("Depart :" + getSource() + "\nArrive:" + getDestination());

		    // AFFICHER jdialog avec slider
		    JDialogManoeuvre.getInstance(pihm, getSource(), getDestination());
		    setSource(null);
		    setDestination(null);
		} else {
		    pihm.modifierTexte("Arrive impossible car chemin inexistant\nentre " + getSource() + " et "
				       + pays_clic);
		}
	    }
	} else {
	    pihm.modifierTexte("Veuillez choisir un pays que vous controlez !");
	}
    }

    @Override
    /**
     * gestion d'evenements du clic de la souris
     * @param e - evenement declancheur
     */
    public void mouseClicked(MouseEvent e) {
        //on recupere la copie de l'image
	Color	c = new Color(copie.getRGB(e.getX(), e.getY()));
	String	s = dicoCoulNom.get(c);

	if (s != null) {

	    // recupere le pays choisi
	    Pays	pays_clic = pihm.getRisk().getPays(s);

	    switch (pihm.getRisk().getPhase()) {
            //debut    
	    case Jeu.INITIALISATION :
		if (renfort(pays_clic)) {
		    pihm.getRisk().phaseSuivante();
                    
                    //DEBUG
		    //System.out.println("(ic) PHASE SUIVANT");
		}

		break;
            //renfort
	    case Jeu.RENFORT :
		renfort(pays_clic);

		break;
            //attaque
	    case Jeu.ATTAQUE :
		attaque(pays_clic);

		break;
            //manoeuvre
	    case Jeu.MANOEUVRE :
		manoeuvre(pays_clic);

		break;
    
	    default :
		System.out.println("Erreur dans mouseClicked : pas de phase");

		break;
	    }
	}

	repaint();
    }
    
    @Override
    /**
     * gestion du deplacement de la souris sur la carte
     * @param e - evenement declancheur
     */
    public void mouseMoved(MouseEvent e) {

	// teste pour voir si on n'est pas en dehors des marges de l'image
	if ((e.getX() < img.getWidth()) && (e.getY() < img.getHeight())) {

	    // on recupere la couleur sur laquelle la souris passe
	    Color	c = new Color(img.getRGB(e.getX(), e.getY()));

	    // si on ets tjs sur le meme pays (on a donc pas quite l'aire de la couleur
	    // qu'on etait en train de survoler
	    if (bloque == false) {

		// on recupere la couleur du dictionnaire
		String	s = dicoCoulNom.get(c);

		// si c'est la meme et de plus cette couleur cerresponde a un pays dans le fichier texte
		if ((oldColor.getRGB() != c.getRGB()) && (s != null)) {

		    // donner la nom du pays a txt
		    txt = s;
                    
		    bloque = true;

		    // Retour a la carte normale
		    razCarte();

		    // Surlignage de la zone voulue
		    if (s != null) {
			oldColor = surligner(c);
		    }

		    repaint();
		    bloque = false;
		}
	    }
	}
    }


    @Override
    public void mouseDragged(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e) {}

    @Override
    public void mouseExited(MouseEvent e) {}

    
    @Override
    public void mousePressed(MouseEvent e) {}

    @Override
    public void mouseReleased(MouseEvent e) {}

    @Override
    /**
     * methode de dession sur le panel de la carte des noms des pays
     */
    public void paint(Graphics g) {
	g.clearRect(0, 0, this.getWidth(), this.getHeight());

	/*
	 *  DEBUG
	 * System.out.println("Panel : "+this.getWidth()+"x"+this.getHeight());
	 * System.out.println("Image : "+img.getWidth()+"x"+img.getHeight());
	 * System.out.println("Fenetre : "+f.getWidth()+"x"+f.getHeight());
	 */
	g.drawImage(img, 0, 0, null);

	for (int i = 0; i < vPays.size(); i++) {
	    vPays.get(i).dessiner(g, this);
	}

	//si dans la fenetre options - affiche les noms des pays
	if (isAfficherNomPays()) {
	    for (Enumeration<Color> e = centresDeGravite.keys(); e.hasMoreElements(); ) {
		Color	c = e.nextElement();
		Point	p = centresDeGravite.get(c);
		String	s = dicoCoulNom.get(c);

		g.setColor(Color.BLACK);
		g.setFont(new Font("Arial", Font.BOLD, 11));
		s = s.toUpperCase();

		int	tailleTexte = g.getFontMetrics().stringWidth(s);

		// mettre le nom du pays au millieu
		g.drawString(s, p.x + MARGE_TEXTE - tailleTexte / 2, p.y - MARGE_TEXTE * 2);
                
                //AVANT le nom du pays etait mis un peu plus a droite
		// g.drawString(s, p.x + MARGE_TEXTE, p.y - MARGE_TEXTE * 2);
	    }

	    // retire le tooltip
	    setToolTipText(null);
	} else {

	    // maj le tooltip avec le nom du pays
	    setToolTipText(txt);
	}
    }

    /**
     * remise a zero de la carte
     */
    public void razCarte() {
	try {
	    img = ImageIO.read(new File(image));
	    setCopie(ImageIO.read(new File(image)));
	} catch (IOException e) {
	    e.printStackTrace();
	}
    }

    /**
     * methode de remplisage des vecteurs de pixels d'une certaine couleur
     * permet de parcourir que un vecteur des couleurs d'un pays
     * au lieu de parcourir chaque fois toute la carte des qu'on deplacait la souris
     */
    public void remplirDicoPixels() {

	// parcours de l'image de la carte
	for (int i = 0; i < img.getHeight(); i++) {
	    for (int j = 0; j < img.getWidth(); j++) {

		// on recupere la couleur
		Color	c = new Color(img.getRGB(j, i));

		if (dicoCoulNom.containsKey(c)) {

		    // si la couleur n'est pas deja dans le dictionnaire
		    // on initialise son vecteur de points et on l'ajoute au dictionnaire
		    if (!dicoPixels.containsKey(c)) {
			Vector<Point>	v = new Vector<Point>();

			dicoPixels.put(c, v);
		    }

		    // remplissage du vecteur de points
		    Vector<Point>	vPoints = dicoPixels.get(c);

		    vPoints.add(new Point(j, i));
		}
	    }
	}
    }

    /**
     * phase renfort
     * @param pays_clic pays choisi
     */
    private boolean renfort(Pays pays_clic) {
	int	retour;
        //teste si on est bien sur un pays nous appartenant
	if (pays_clic.controlePays(pihm.getRisk().getJoueurCourant())) {
	    retour = pihm.getRisk().getJoueurCourant().decrementeReserveArmee();
            //si on n'as plus de soldats
	    if (retour == 0) {
		pihm.modifierTexte("Votre reserve de soldat est vide.");
	    } else {
		pays_clic.ajouteArmee(retour);
	    }
            //si on est en mode connecte on ecrit dans la console
	    if (ConnexionServeurIHM.CONNECTE) {
		pihm.getJtaConsole().append(pihm.getRisk().getTc().envoieInformationsPays(pays_clic) + "\n");
	    }

	    pihm.panelJoueurCourant();

	    return true;
	} else { //si on a clique sur un pays quon ne controle pas
	    pihm.modifierTexte("Veuillez choisir un pays que vous controlez !");

	    return false;
	}
    }

    /**
     * methode qui surligne un pays en fonction de la couleur predominante de ses pixels
     * @param c - couleur utilisee pour le surlinage
     * @return la couleur plus claire ou plus foncee
     */
    public Color surligner(Color c) {
	int	clair = 0;

	// si dans la fenetre des options le radio button de la mise en surbrillance en couleur est active
	if (isSurligner_couleur()) {

	    // si la couleur du pays est claire alors on assombrit sa couleur
	    if (((c.getRed() + c.getGreen() + c.getBlue()) / 3.0) > 122.5) {
		clair = c.darker().getRGB();
	    }    // sinon on l'eclaircit
		    else {
		clair = c.brighter().getRGB();
	    }
	} else { //si dans la fenetre des options le radio button de la mise en surbrillance en gris est active

	    // si la couleur du pays est claire alors on surligne en dark_gray
	    if (((c.getRed() + c.getGreen() + c.getBlue()) / 3.0) > 122.5) {
		clair = Color.DARK_GRAY.getRGB();
	    }    // sinon on surligne en light_gray
		    else {
		clair = Color.LIGHT_GRAY.getRGB();
	    }
	}

	Vector<Point>	v = dicoPixels.get(c);
        //mettre en surbrillance tous les pixels d'un meme pays
	for (int i = 0; i < v.size(); i++) {
	    Point	p = v.get(i);

	    img.setRGB(p.x, p.y, clair);
	}

	return new Color(clair);
    }

    /**
     * methode de surlignage des pays source et destination dans mouse clicked
     */
    public void surlignerPays() {
	for (int i = 0; i < vPays.size(); i++) {
	    if ((getSource() != null) && vPays.get(i).getPays().getNom().equals(getSource().getNom())) {
		vPays.get(i).clique = true;
	    } else if ((getDestination() != null)
		       && vPays.get(i).getPays().getNom().equals(getDestination().getNom())) {
		vPays.get(i).clique = true;
	    } else {
		vPays.get(i).clique = false;
	    }
	}
    }

    /**
     * getter
     * recupere la copie de l'image de la carte
     * @return la copie de l'image de la carte
     */
    public BufferedImage getCopie() {
	return copie;
    }
    /**
     * getter
     * recupere le 2eme pays choisit lors d'un attaque ou une manoeuvre
     * @return - la pays destination ou defenseur
     */
    public Pays getDestination() {
	return destination;
    }

    /**
     * getter sur la table de hachage dicoCoulNom   
     * @return la table de hachage dicoCoulNom contennant le code RGB et le nom du pays
     */
    public Hashtable<Color, String> getDicoCoulNom() {
	return dicoCoulNom;
    }

    /**
     * getter sur le dictionnaire des pixels des pays
     * @return la table de hachage dicoPixels contenant la couleur ainsi 
     * que le vecteur des pixels de la meme couleur d'un pays
     */
    public Hashtable<Color, Vector<Point>> getDicoPixels() {
	return dicoPixels;
    }

    /**
     * getter sur l'image de la carte
     * @return l'image de la carte
     */
    public BufferedImage getImg() {
	return img;
    }
    /**
     * recupere le pays clique
     * @return - le pays source sur lequel on a clique
     */
    public Pays getSource() {
	return source;
    }

    /**
     * verifie si le checkbox pour afficher le nom d'un pays a ete active
     * @return true ou false
     */
    public boolean isAfficherNomPays() {
	return afficherNomPays;
    }

    /**
     * verifie si le checkbox pour afficher les possesions des joueurs a ete active
     * @return true ou false
     */
    public boolean isAfficherPossessions() {
	return afficherPossessions;
    }

    /**
     * verifie si le radiobutton pour mettre en surbrillance en couleur a ete active
     * @return true ou false
     */
    public boolean isSurligner_couleur() {
	return surligner_couleur;
    }

    /**
     * setter
     * donne une nouvelle valeur au boolean afficherNomPays
     * @param afficherNomPays - nouvelle valeur du boolean 
     */
    public void setAfficherNomPays(boolean afficherNomPays) {
	this.afficherNomPays = afficherNomPays;
    }

    /**
     * setter
     * donne une nouvelle valeur au boolean afficherPossessions
     * @param afficherPossessions - nouvelle valeur du boolean 
     */
    public void setAfficherPossessions(boolean afficherPossessions) {
	this.afficherPossessions = afficherPossessions;
    }

    /**
     * setter sur la copie de l'image de la carte
     * @param copie - la nouvelle copie de la carte
     */
    public void setCopie(BufferedImage copie) {
	this.copie = copie;
    }
    
    /**
     * setter sur le pays destination
     * @param destination - nouveau pays destination
     */
    public void setDestination(Pays destination) {
	this.destination = destination;
    }

    /**
     * setter sur la table de hachage contenant le code RGB et les noms des pays
     * @param dicoCoulNom - la nouvelle table de hachage
     */
    public void setDicoCoulNom(Hashtable<Color, String> dicoCoulNom) {
	this.dicoCoulNom = dicoCoulNom;
    }

    /**
     * setter sur le dictionnaire des pixels d'une meme couleur
     * @param dicoPixels - la nouvelle table de hachage des points de la meme couleur
     */
    public void setDicoPixels(Hashtable<Color, Vector<Point>> dicoPixels) {
	this.dicoPixels = dicoPixels;
    }

    /**
     * setter sur l'image de la carte
     * @param img - la nouvelle image 
     */
    public void setImg(BufferedImage img) {
	this.img = img;
    }
    /**
     * setter sur le pays source clique
     * @param source - la nouveau pays source
     */
    public void setSource(Pays source) {
	this.source = source;
    }

    /**
     * setter 
     * @param surligner_couleur - la nouvelle valeur du boolean
     */
    public void setSurligner_couleur(boolean surligner_couleur) {
	this.surligner_couleur = surligner_couleur;
    }
}
